package lol.clann.minecraft.springboot.plugin.bukkit.impl;

import lol.clann.minecraft.springboot.api.bukkit.model.bank.Bank;
import lol.clann.minecraft.springboot.api.bukkit.model.bank.BankResult;
import lol.clann.minecraft.springboot.api.bukkit.model.bank.TransformResult;
import lol.clann.minecraft.springboot.api.bukkit.utils.BankUtils;
import lol.clann.minecraft.springboot.plugin.bukkit.mapper.BankMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

/**
 *
 * @author pyz
 * @date 2019/8/18 5:10 PM
 */
@Service
public class BankUtilsImpl implements BankUtils {

    @Autowired
    private BankMapper bankMapper;

    /**
     * 用于查询
     * 获取指定账户
     * 若不存在,会创建
     * @param playerName
     * @param onlineBankType
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Bank getBank(String playerName, String onlineBankType) {
        Bank bank = bankMapper.findBank(playerName, onlineBankType);
        if (bank == null) {
            bank = createBank(playerName, onlineBankType);
        }
        return bank;
    }

    /**
     * 用于交易
     * 获取并锁定指定账户
     * 若不存在,会创建
     * 必须在事物中执行
     * @param playerName
     * @param onlineBankType
     * @return
     */
    @Override
    public Bank getAndLockBank(String playerName, String onlineBankType) {
//         确保在事物中
        TransactionAspectSupport.currentTransactionStatus();
        Bank bank = getBank(playerName, onlineBankType);
        bank = bankMapper.getAndLockBank(bank.getId());
        return bank;
    }

    @Transactional(rollbackFor = Throwable.class)
    protected Bank createBank(String playerName, String onlineBankType) {
        try {
            bankMapper.lockBankTable();
            Bank bank = bankMapper.findBank(playerName, onlineBankType);
            if (bank != null) {
                return bank;
            }
            bank = new Bank();
            bank.setPlayer(playerName);
            bank.setType(onlineBankType);
            bankMapper.insertBank(bank);
            return bank;
        } finally {
            bankMapper.unlockBankTable();
        }
    }

    /**
     * 充值
     *
     * @param bank
     * @param amount
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public BankResult pay(Bank bank, double amount) {
        if (amount == 0) {
            return BankResult.builder().status(201).errorMsg("支付金额为0").build();
        }
        if (amount < 0) {
            return BankResult.builder().status(202).errorMsg("支付金额为负").build();
        }
        Bank persistBank = bankMapper.getAndLockBank(bank.getId());
        bankMapper.pay(persistBank.getId(), amount);
        persistBank = bankMapper.getAndLockBank(persistBank.getId());
        bank.setAmount(persistBank.getAmount());
        return BankResult.builder().amount(bank.getAmount()).status(200).build();
    }

    /**
     * 扣款
     *
     * @param bank 账户
     * @param amount
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public BankResult withdraw(Bank bank, double amount) {
        if (amount == 0) {
            return BankResult.builder().status(301).errorMsg("扣款金额为0").build();
        }
        if (amount < 0) {
            return BankResult.builder().status(302).errorMsg("扣款金额为负").build();
        }
        Bank persistBank = bankMapper.getAndLockBank(bank.getId());
        if (persistBank.getAmount() < amount) {
            return BankResult.builder().status(303).errorMsg("余额不足").build();
        }
        bankMapper.pay(persistBank.getId(), -amount);
        persistBank = bankMapper.getAndLockBank(persistBank.getId());
        bank.setAmount(persistBank.getAmount());
        return BankResult.builder().amount(bank.getAmount()).status(200).build();
    }

    /**
     * 转账
     *
     * @param from 转出账户
     * @param to    转入账户
     * @param amount
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public TransformResult transform(Bank from, Bank to, double amount) {
        Bank persistFromBank = bankMapper.getAndLockBank(from.getId());
        Bank persistToBank = bankMapper.getAndLockBank(to.getId());
        if (persistFromBank.getAmount() < amount) {
            return TransformResult.builder().status(201).errorMsg("转出账户余额不足").build();
        }
        bankMapper.pay(persistFromBank.getId(), -amount);
        bankMapper.pay(persistToBank.getId(), amount);
        persistFromBank = bankMapper.getBank(persistFromBank.getId());
        from.setAmount(persistFromBank.getAmount());
        persistToBank = bankMapper.getBank(persistToBank.getId());
        to.setAmount(persistToBank.getAmount());
        return TransformResult.builder().fromBankAmount(from.getAmount()).toBankAmount(to.getAmount()).status(200).build();
    }
}
